{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "38d84418",
   "metadata": {},
   "source": [
    "# Assigning Geometric Properties\n",
    "\n",
    "Geometric properties refer to the physical sizes of the pores and throats, such as pore diameter and throat lengths. The values are essential to the pore network modeling enterprize since they control all the transport and percolation behavior of the network. Unlike phase properties which can be normalized for, geometric properties define the network even more than topological properties like connectivity. \n",
    "\n",
    "Geometric properties *can* be calculated by various means, ranging from assigning random values to pores, to extracting values from tomographic images. OpenPNM provides a library of functions, or 'pore-scale models' which can calculate these geometric properties automatically. This tutorial will cover the following subjects:\n",
    "\n",
    "- Manually Calculating Pore and Throat Properties (⚠ Not Recommended!) \n",
    "- Using Pore-scale Models from the Library \n",
    "- Overview of the Dependency Handler \n",
    "- Using Predefined Collections of Models \n",
    "- Defining Heterogeneous Domains (by Applying Models to Specific Locations) \n",
    "- Customizing Models (by Overwriting Them or Their Arguments) \n",
    "- Writing and Using Custom Models "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "94917bac",
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "import openpnm as op\n",
    "op.visualization.set_mpl_style()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f63bbaee",
   "metadata": {},
   "source": [
    "Let's start by creating a blank Cubic network.  As we can see by printing it, there are only coordinates, connections, and some labels, but no geometric properties:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "142050f5",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "══════════════════════════════════════════════════════════════════════════════\n",
      "net : <openpnm.network.Cubic at 0x26c1d52b720>\n",
      "――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――\n",
      "  #  Properties                                                   Valid Values\n",
      "――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――\n",
      "  2  pore.coords                                                   8000 / 8000\n",
      "  3  throat.conns                                                22800 / 22800\n",
      "――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――\n",
      "  #  Labels                                                 Assigned Locations\n",
      "――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――\n",
      "  2  pore.surface                                                         2168\n",
      "  3  throat.surface                                                       4332\n",
      "  4  pore.left                                                             400\n",
      "  5  pore.right                                                            400\n",
      "  6  pore.front                                                            400\n",
      "  7  pore.back                                                             400\n",
      "  8  pore.bottom                                                           400\n",
      "  9  pore.top                                                              400\n",
      "――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――\n"
     ]
    }
   ],
   "source": [
    "np.random.seed(0)\n",
    "pn = op.network.Cubic([20, 20, 20], spacing=5e-5)\n",
    "print(pn)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d7e40b76",
   "metadata": {},
   "source": [
    "```{attention} **Changed in V3**\n",
    "\n",
    "  In OpenPNM V3 we have removed the concept of ``Geometry`` and ``Physics`` objects, in favor of placing all the properties on the ``Network`` and ``Phase`` objects instead. \n",
    "  \n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "35629fd2",
   "metadata": {},
   "source": [
    "To add geometrical properties to a network, we have a few different options.  Each will be explored below:"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "51da4915",
   "metadata": {},
   "source": [
    "## Manually Calculating Properties\n",
    "\n",
    "```{warning} **Manual Calculation is Not Recommended**\n",
    "\n",
    "  This is *not* the preferred way to do things, but does illustrate the processes very well. The preferred way is using pore-scale models, which allow for the automatic regeneration of dependent properties  when something changes. \n",
    "  \n",
    "```\n",
    "\n",
    "Let's start by adding pore and throat size distributions.  There are a few different ways to do this, and we'll explore each one to be thorough.  "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f7ad8f43",
   "metadata": {},
   "source": [
    "### Adding pore and throat sizes from `scipy.stats` distributions\n",
    "\n",
    "Scipy's `stats` module has a *lot* of statistical distributions defined.  Let's generate pore and throat sizes using some of these.  First, let's use a normal distribution to generate pore sizes within the range ~1 to 50 um:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "7f638068",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "np.random.seed(0)\n",
    "import scipy.stats as spst\n",
    "psd = spst.norm.rvs(loc=25, scale=6, size=pn.Np)\n",
    "plt.hist(psd, edgecolor='k')\n",
    "plt.xlim([0, 50]);"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "da11cebf",
   "metadata": {},
   "source": [
    "The above distribution looks good, let's just make absolutely sure that our distribution is not so wide that it has negative numbers or values greater than 50 um:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "8efcd33a",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2.5593961722893255\n",
      "47.80996128980269\n"
     ]
    }
   ],
   "source": [
    "print(psd.min())\n",
    "print(psd.max())"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "59b3a0eb",
   "metadata": {},
   "source": [
    "Now we'll convert these values to SI and assign to the network:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "98c6c031",
   "metadata": {},
   "outputs": [],
   "source": [
    "pn['pore.diameter'] = psd*1e-6  # um to m"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d3e52c17",
   "metadata": {},
   "source": [
    "Next we need to define throat diameters. We can do this in the same way, but let's use a different distribution.  Note that this approach is not recommended because as we'll see it results in throats that are larger than the two pores they are connected two.  We'll fix this in the following section:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "3dd8c095",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "np.random.seed(0)\n",
    "tsd = spst.weibull_min.rvs(c=1.5, loc=.5, scale=7.5, size=pn.Nt)\n",
    "plt.hist(tsd, edgecolor='k')\n",
    "plt.xlim([0, 50]);"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "60cc7cb1",
   "metadata": {},
   "source": [
    "Again, let's inspect the high and low values:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "6dee2380",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0.5130345457395142\n",
      "36.96861960231873\n"
     ]
    }
   ],
   "source": [
    "print(tsd.min())\n",
    "print(tsd.max())"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9fb4889c",
   "metadata": {},
   "source": [
    "So we can see that we have throats as small as 500 nm, and as large as 37 um.  These can be assigned to the network as well:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "e1cf0757",
   "metadata": {},
   "outputs": [],
   "source": [
    "pn['throat.diameter'] = tsd*1e-6  # um to m"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "73a09aab",
   "metadata": {},
   "source": [
    "The problem with this approach is that both pore and throat sizes were just assigned to random locations, rather than putting small throats between small pores and vice-versa. When throats are larger than the pores they connect it can cause problems or strangeness in the results since we generally assume a throat is a constriction between two pores.  Let's count how many are problematic."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "a6e0cbbd",
   "metadata": {},
   "outputs": [],
   "source": [
    "hits = np.any(pn['pore.diameter'][pn.conns].T < pn['throat.diameter'], axis=0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "b27b6342",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "564"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "hits.sum()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f403af58",
   "metadata": {},
   "source": [
    "```{tip}\n",
    "\n",
    " **Indexing pore properties by conns:** Using the `conns` array to index into a pore property returns an Nt-by-2 array with the properties of the pores on the end of a throat in each column.  For instance, see the diameter of the pore on each end of a throat, use `pn['pore.diameter'][pn.conns]`.  This approach is very powerful.  If you ever feel tempted to use a for-loop to scan over each pore, then inspect the properties of the neighboring throats, consider instead if you can \"loop\" over the throats then interrogate  each pore.  If yes, then you can use this conns-indexing trick.\n",
    "    \n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0eb07950",
   "metadata": {},
   "source": [
    "There are two *safer* ways to assign pore and throat sizes, to ensure that throats are smaller than the pores they connected.  The first is to proceed as above by assigning pore sizes randomly, *then* assigning throats to be the *as small (or smaller) as the smallest pore it is connected to*.  This can be done using some `numpy` functions as follows:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "369bc582",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "tsd = np.amin(pn['pore.diameter'][pn.conns], axis=1)\n",
    "plt.hist(tsd, edgecolor='k', density=True, alpha=0.5)\n",
    "plt.hist(pn['pore.diameter'], edgecolor='k', density=True, alpha=0.5)\n",
    "plt.xlim([0, 50e-6]);"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c15ad2b2",
   "metadata": {},
   "source": [
    "We can see from the above plot that the throat sizes are similar to the pore sizes, which is expected since they are taken from the pore sizes values. However, we can also see a small shift to the left, which is also expected given that the throats always take on the size of the smaller pore, creating a bias towards smaller sizes."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "acce746c",
   "metadata": {},
   "source": [
    "It may also be desirable to force the throats to be smaller than the two neighboring pores by some factor:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "ceca301c",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "pn['throat.diameter'] = tsd*0.5\n",
    "plt.hist(pn['throat.diameter'], edgecolor='k', density=True, alpha=0.5)\n",
    "plt.hist(pn['pore.diameter'], edgecolor='k', density=True, alpha=0.5)\n",
    "plt.xlim([0, 50e-6]);"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9d309397",
   "metadata": {},
   "source": [
    "One downside of the above approach is that you no longer have control over the shape and distribution of the throat sizes. This can be solved by applying the same approach just described but to *random seeds* instead of actual sizes. Then the random seeds can be put into a cumulative density function to compute the corresponding size.  This is demonstrated below:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "a5300fc4",
   "metadata": {},
   "outputs": [],
   "source": [
    "lo, hi = 0.01, 0.99\n",
    "pn['pore.seed'] = np.random.rand(pn.Np)*(hi - lo) + lo"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8dae3979",
   "metadata": {},
   "source": [
    "```{tip}\n",
    "  Setting the `lo` and `hi` values of the seeds prevents values that lie far out in the tail of a distribution from occurring which can lead to overly large pores or throats.\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8a1c8006",
   "metadata": {},
   "source": [
    "The `ppf` function, or *point probability function* returns the value of a cumulative distribution at the given probability, so the seed values computed above can be related to size values using:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "26d114de",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "import scipy.stats as spst\n",
    "psd = spst.norm.ppf(loc=25, scale=6, q=pn['pore.seed'])\n",
    "pn['pore.diameter'] = psd*1e-6\n",
    "plt.hist(pn['pore.diameter'], edgecolor='k')\n",
    "plt.xlim([0, 50e-6]);"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a5adfbfa",
   "metadata": {},
   "source": [
    "Now we can find the throat seed values as the *minimum pore seed* value of the two neighboring pores:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "8b88f316",
   "metadata": {},
   "outputs": [],
   "source": [
    "pn['throat.seed'] = np.amin(pn['pore.seed'][pn.conns], axis=1)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5d1c6c94",
   "metadata": {},
   "source": [
    "And then we can use these seed values in the `ppf` function of the desired distribution. So long as the distribution does not create larger values than the distribution used to compute pore sizes, then the throat sizes will always be smaller."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "895c820d",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYcAAAEFCAYAAAAIZiutAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8/fFQqAAAACXBIWXMAAAsTAAALEwEAmpwYAAAaxElEQVR4nO3df4zV9Z3v8eerUBRpEdSBpTPcQFfsrpLUyoTLLunmWrrL7G4tZKPJNLeVGMxsDdvF671pwD+u1ASjzU3tYq4mtHQFty1Q2grbG90SqOntlR06KJZfAlNpYZYZZsAfYIwo4/v+cT5TzpzvmTlnZg6cM/J6JCff73l/v58Pn++J8TXfH+dzFBGYmZnl+0i1B2BmZrXH4WBmZhkOBzMzy3A4mJlZhsPBzMwyxlZ7AMN1ww03xIwZM6o9DDOzUWXPnj2nI6Ku1H6jNhxmzJhBW1tbtYdhZjaqSPp9Ofv5spKZmWU4HMzMLKOscJD03yQdkLRf0g8lXS3pOknbJR1Ny8l5+6+U1C7psKSFefU5kvalbWskKdWvkrQp1Vslzaj4kZqZWdlKhoOkeuAfgcaImA2MAZqBFcCOiJgF7EjvkXRz2n4L0AQ8KWlM6u4poAWYlV5Nqb4UeCMibgQeBx6ryNGZmdmwlHtZaSwwXtJY4BrgJLAIWJ+2rwcWp/VFwMaIOB8Rx4B2YK6kacDEiNgVuQmdNhS06etrC7Cg76zCzMwuv5LhEBH/Afwv4DjQCbwVET8HpkZEZ9qnE5iSmtQDJ/K66Ei1+rReWO/XJiIuAG8B1xeORVKLpDZJbT09PeUeo5mZDVE5l5Umk/vLfibwCWCCpC8P1qRILQapD9amfyFibUQ0RkRjXV3Jx3TNzGyYyrms9HngWET0RMT7wE+APwdOpUtFpGV32r8DmJ7XvoHcZaiOtF5Y79cmXbq6Fnh9OAdkZmYjV044HAfmSbom3QdYABwCtgFL0j5LgK1pfRvQnJ5AmknuxvPudOnpnKR5qZ+7C9r09XUnsDP8QxNmZlVT8hvSEdEqaQvwEnABeBlYC3wM2CxpKbkAuSvtf0DSZuBg2n9ZRPSm7u4DngbGA8+lF8A64BlJ7eTOGJorcnRmg3jokW/S0XV6RH00/NENfOPBr1doRGa1o6zpMyLiIeChgvJ5cmcRxfZfDawuUm8DZhepv0sKF7PLpaPrNLPvuHdEfez/1+9WaDRmtcXfkDYzswyHg5mZZTgczMwsw+FgZmYZDgczM8twOJiZWYbDwczMMhwOZmaW4XAwM7MMh4OZmWWUNX2GWS2pxJxIAHv37Wf2HRUYkNmHkMPBRp1KzIkE8OLur1ZgNGYfTr6sZGZmGQ4HMzPLcDiYmVmGw8HMzDIcDmZmluFwMDOzjJLhIOlTkvbmvc5Kul/SdZK2SzqalpPz2qyU1C7psKSFefU5kvalbWskKdWvkrQp1VslzbgkR2tmZmUpGQ4RcTgibo2IW4E5wDvAT4EVwI6ImAXsSO+RdDPQDNwCNAFPShqTunsKaAFmpVdTqi8F3oiIG4HHgccqcnRmZjYsQ72stAD4bUT8HlgErE/19cDitL4I2BgR5yPiGNAOzJU0DZgYEbsiIoANBW36+toCLOg7qzAzs8tvqOHQDPwwrU+NiE6AtJyS6vXAibw2HalWn9YL6/3aRMQF4C3g+sJ/XFKLpDZJbT09PUMcupmZlavscJA0Dvgi8KNSuxapxSD1wdr0L0SsjYjGiGisq6srMQwzMxuuoZw5/DXwUkScSu9PpUtFpGV3qncA0/PaNQAnU72hSL1fG0ljgWuB14cwNjMzq6ChhMOXuHhJCWAbsCStLwG25tWb0xNIM8ndeN6dLj2dkzQv3U+4u6BNX193AjvTfQkzM6uCsmZllXQN8JfA3+eVHwU2S1oKHAfuAoiIA5I2AweBC8CyiOhNbe4DngbGA8+lF8A64BlJ7eTOGJpHcExmZjZCZYVDRLxDwQ3iiDhD7umlYvuvBlYXqbcBs4vU3yWFi5mZVZ9/z8HsEvj2I/+TN0+dKL1jCZOmTuf+Bx+uwIjMhsbhYHYJvHnqBKsW3zTiflY9e6QCozEbOs+tZGZmGQ4HMzPLcDiYmVmGw8HMzDIcDmZmluFwMDOzDIeDmZllOBzMzCzDX4IzS1o3raH3bOeQ2rx54iirlmd/W+Tgvr1QgS/BmVWLw8Es6T3byQMLZw6pzW9+eYg/uvr3mfq/nTjO1ue3l93PxAnXcPtn5w/p3za7lBwOZiPwfu8HTLnptkx93ITXitYH0n3kpUoOy2zEfM/BzMwyHA5mZpbhcDAzswyHg5mZZZQVDpImSdoi6VVJhyT9maTrJG2XdDQtJ+ftv1JSu6TDkhbm1edI2pe2rUm/JU36velNqd4qaUbFj9TMzMpW7pnDPwHPR8SfAJ8GDgErgB0RMQvYkd4j6WZyvwF9C9AEPClpTOrnKaAFmJVeTam+FHgjIm4EHgceG+FxmZnZCJQMB0kTgb8A1gFExHsR8SawCFifdlsPLE7ri4CNEXE+Io4B7cBcSdOAiRGxKyIC2FDQpq+vLcCCvrMKMzO7/Mo5c/gk0AP8s6SXJX1X0gRgakR0AqTllLR/PZD/47kdqVaf1gvr/dpExAXgLeD6woFIapHUJqmtpyf7rVQzM6uMcr4ENxa4DfhaRLRK+ifSJaQBFPuLPwapD9amfyFiLbAWoLGxMbPdat9Dj3yTjq7TI+pj7779zL6jQgMys6LKCYcOoCMiWtP7LeTC4ZSkaRHRmS4ZdeftPz2vfQNwMtUbitTz23RIGgtcC7w+jOOxGtfRdZrZd9w7oj5e3P3VCo3GzAZS8rJSRHQBJyR9KpUWAAeBbcCSVFsCbE3r24Dm9ATSTHI3nnenS0/nJM1L9xPuLmjT19edwM50X8LMzKqg3LmVvgZ8X9I44DXgHnLBslnSUuA4cBdARByQtJlcgFwAlkVEb+rnPuBpYDzwXHpB7mb3M5LayZ0xNI/wuMzMbATKCoeI2As0Ftm0YID9VwOri9TbgNlF6u+SwsXMzKrP35A2M7MMh4OZmWU4HMzMLMPhYGZmGQ4HMzPLcDiYmVmGw8HMzDIcDmZmluFwMDOzDIeDmZllOBzMzCzD4WBmZhnlzspqZlXwyt6XWbX8nor0NWnqdO5/8OGK9GUffg4HsxoW773DqsU3VaSvVc8eqUg/dmXwZSUzM8vwmYONaq2b1tB7tnNYbcedeZUXv7PyD+9PHzsEzKzQyMxGN4eDjWq9Zzt5YOHw/oe+Z9wB5tx+se2KJ/ZUalhmo15Zl5Uk/U7SPkl7JbWl2nWStks6mpaT8/ZfKald0mFJC/Pqc1I/7ZLWpN+SJv3e9KZUb5U0o8LHaWZmQzCUew63R8StEdH3c6ErgB0RMQvYkd4j6WZyvwF9C9AEPClpTGrzFNACzEqvplRfCrwRETcCjwOPDf+QzMxspEZyQ3oRsD6trwcW59U3RsT5iDgGtANzJU0DJkbErogIYENBm76+tgAL+s4qzMzs8is3HAL4uaQ9klpSbWpEdAKk5ZRUrwdO5LXtSLX6tF5Y79cmIi4AbwHXFw5CUoukNkltPT09ZQ7dzMyGqtwb0vMj4qSkKcB2Sa8Osm+xv/hjkPpgbfoXItYCawEaGxsz283MrDLKOnOIiJNp2Q38FJgLnEqXikjL7rR7BzA9r3kDcDLVG4rU+7WRNBa4Fnh96IdjZmaVUDIcJE2Q9PG+deCvgP3ANmBJ2m0JsDWtbwOa0xNIM8ndeN6dLj2dkzQv3U+4u6BNX193AjvTfQkzM6uCci4rTQV+mu4PjwV+EBHPS/o1sFnSUuA4cBdARByQtBk4CFwAlkVEb+rrPuBpYDzwXHoBrAOekdRO7oyhuQLHZmZmw1QyHCLiNeDTRepngAUDtFkNrC5SbwNmF6m/SwoXMzOrPs+tZGZmGQ4HMzPLcDiYmVmGw8HMzDIcDmZmluFwMDOzDIeDmZllOBzMzCzD4WBmZhkOBzMzy3A4mJlZhsPBzMwyHA5mZpbhcDAzswyHg5mZZTgczMwsw+FgZmYZZYeDpDGSXpb0s/T+OknbJR1Ny8l5+66U1C7psKSFefU5kvalbWvSb0mTfm96U6q3SppRwWM0M7MhGsqZw3LgUN77FcCOiJgF7EjvkXQzud+AvgVoAp6UNCa1eQpoAWalV1OqLwXeiIgbgceBx4Z1NGZmVhFlhYOkBuBvge/mlRcB69P6emBxXn1jRJyPiGNAOzBX0jRgYkTsiogANhS06etrC7Cg76zCzMwuv3LPHL4NfB34IK82NSI6AdJySqrXAyfy9utItfq0Xljv1yYiLgBvAdeXexBmZlZZJcNB0heA7ojYU2afxf7ij0Hqg7UpHEuLpDZJbT09PWUOx8zMhqqcM4f5wBcl/Q7YCHxO0r8Ap9KlItKyO+3fAUzPa98AnEz1hiL1fm0kjQWuBV4vHEhErI2IxohorKurK+sAzcxs6EqGQ0SsjIiGiJhB7kbzzoj4MrANWJJ2WwJsTevbgOb0BNJMcjeed6dLT+ckzUv3E+4uaNPX153p38icOZiZ2eUxdgRtHwU2S1oKHAfuAoiIA5I2AweBC8CyiOhNbe4DngbGA8+lF8A64BlJ7eTOGJpHMC4zMxuhIYVDRLwAvJDWzwALBthvNbC6SL0NmF2k/i4pXMzMrPr8DWkzM8twOJiZWYbDwczMMhwOZmaW4XAwM7MMh4OZmWU4HMzMLGMkX4IzG7bWTWvoPds5rLbjzrzKi99ZCcDpY4eAmRUcmZmBw8HK9NAj36Sj6/SI+9m7bz+z74Des508sHB4/1PfM+4Ac27PtV3xRLnzQZrZUDgcrCwdXaeZfce9I+7nxd1frcBoPny6urrY+vz2TP3U6TNF6wOZOOEabv/s/EoOza5QDgezGvB+7wdMuem2TH3chNeK1gfSfeSlAbe9svdlVi2/Z1jjyzdp6nTuf/DhEfdjtc3hYHaFiPfeYdXim0bcz6pnj1RgNFbr/LSSmZllOBzMzCzD4WBmZhkOBzMzy3A4mJlZhsPBzMwySoaDpKsl7Zb0iqQDkr6R6tdJ2i7paFpOzmuzUlK7pMOSFubV50jal7atkaRUv0rSplRvlTTjEhyrmZmVqZwzh/PA5yLi08CtQJOkecAKYEdEzAJ2pPdIuhloBm4BmoAnJY1JfT0FtACz0qsp1ZcCb0TEjcDjwGMjPzQzMxuukuEQOW+ntx9NrwAWAetTfT2wOK0vAjZGxPmIOAa0A3MlTQMmRsSuiAhgQ0Gbvr62AAv6zirMzOzyK+ueg6QxkvYC3cD2iGgFpkZEJ0BaTkm71wMn8pp3pFp9Wi+s92sTEReAt4Dri4yjRVKbpLaenp6yDtDMzIaurHCIiN6IuBVoIHcWMHuQ3Yv9xR+D1AdrUziOtRHRGBGNdXV1JUZtZmbDNaSnlSLiTeAFcvcKTqVLRaRld9qtA5ie16wBOJnqDUXq/dpIGgtcC7w+lLGZmVnllPO0Up2kSWl9PPB54FVgG7Ak7bYE2JrWtwHN6QmkmeRuPO9Ol57OSZqX7ifcXdCmr687gZ3pvoSZmVVBObOyTgPWpyeOPgJsjoifSdoFbJa0FDgO3AUQEQckbQYOAheAZRHRm/q6D3gaGA88l14A64BnJLWTO2NorsTBmZnZ8JQMh4j4DfCZIvUzwIIB2qwGVheptwGZ+xUR8S4pXMzMrPr8DWkzM8twOJiZWYbDwczMMhwOZmaW4XAwM7MMh4OZmWU4HMzMLMPhYGZmGQ4HMzPLcDiYmVmGw8HMzDIcDmZmluFwMDOzDIeDmZllOBzMzCzD4WBmZhkOBzMzyyjnN6SnS/qFpEOSDkhanurXSdou6WhaTs5rs1JSu6TDkhbm1edI2pe2rUm/JU36velNqd4qacYlOFYzMytTOWcOF4D/HhF/CswDlkm6GVgB7IiIWcCO9J60rRm4BWgCnky/Pw3wFNACzEqvplRfCrwRETcCjwOPVeDYzMxsmEqGQ0R0RsRLaf0ccAioBxYB69Nu64HFaX0RsDEizkfEMaAdmCtpGjAxInZFRAAbCtr09bUFWNB3VmFmZpffkO45pMs9nwFagakR0Qm5AAGmpN3qgRN5zTpSrT6tF9b7tYmIC8BbwPVF/v0WSW2S2np6eoYydDMzG4Kyw0HSx4AfA/dHxNnBdi1Si0Hqg7XpX4hYGxGNEdFYV1dXashmZjZMY8vZSdJHyQXD9yPiJ6l8StK0iOhMl4y6U70DmJ7XvAE4meoNRer5bTokjQWuBV4fxvHYJdS6aQ29ZztH1Me4M6/y4ndWcvrYIWBmZQZmZhVXMhzStf91wKGI+Fbepm3AEuDRtNyaV/+BpG8BnyB343l3RPRKOidpHrnLUncDTxT0tQu4E9iZ7ktYDek928kDC0f2P/Q94w4w5/aZrHhiT4VGZWaXQjlnDvOBrwD7JO1NtQfJhcJmSUuB48BdABFxQNJm4CC5J52WRURvancf8DQwHnguvSAXPs9Iaid3xtA8ssMyM7ORKBkOEfErit8TAFgwQJvVwOoi9TZgdpH6u6RwMTOz6ivrnoOZWZ9X9r7MquX3VKSvSVOnc/+DD1ekL6ssh8MV4KFHvklH1+kR9bF3334+WTe+QiOy0Szee4dVi2+qSF+rnj1SkX6s8hwOV4COrtPMvuPeEfXx4u6vkrtVZGZXAk+8Z2ZmGQ4HMzPLcDiYmVmGw8HMzDIcDmZmluFwMDOzDIeDmZllOBzMzCzDX4Iz+xDp6upi6/Pbi247dfrMgNvyTZxwDbd/dn6lh2ajjMPB7EPk/d4PmHLTbUW3jZvw2oDb8nUfeanSw7JRyJeVzMwsw+FgZmYZDgczM8twOJiZWUbJcJD0PUndkvbn1a6TtF3S0bScnLdtpaR2SYclLcyrz5G0L21bk36bGklXSdqU6q2SZlT4GM3MbIjKOXN4GmgqqK0AdkTELGBHeo+km8n9/vMtqc2TksakNk8BLcCs9OrrcynwRkTcCDwOPDbcgzEzs8ooGQ4R8Uvg9YLyImB9Wl8PLM6rb4yI8xFxDGgH5kqaBkyMiF0REcCGgjZ9fW0BFvSdVZiZWXUM957D1IjoBEjLKaleD5zI268j1erTemG9X5uIuAC8BVw/zHGZmVkFVPqGdLG/+GOQ+mBtsp1LLZLaJLX19PQMc4hmZlbKcMPhVLpURFp2p3oHMD1vvwbgZKo3FKn3ayNpLHAt2ctYAETE2ohojIjGurq6YQ7dzMxKGe70GduAJcCjabk1r/4DSd8CPkHuxvPuiOiVdE7SPKAVuBt4oqCvXcCdwM50X8Iq5Ngr/4+zXb8dUR/jzrzK6d5JwMyKjMnMalvJcJD0Q+C/ADdI6gAeIhcKmyUtBY4DdwFExAFJm4GDwAVgWUT0pq7uI/fk03jgufQCWAc8I6md3BlDc0WOzP5gzHvneGDhn42ojz3jDvCj/e9UaERmVutKhkNEfGmATQsG2H81sLpIvQ2YXaT+LilczMysNvgb0mZmluEpu82sal7Z+zKrlt9Tkb4mTZ3O/Q8+XJG+zOFgZlUU773DqsU3VaSvVc8eqUg/luPLSmZmluFwMDOzDIeDmZllOBzMzCzD4WBmZhkOBzMzy3A4mJlZhsPBzMwy/CU4M+unq6uLrc9vH3D7qdNnBt3eZ+KEa7j9s/MrOTS7jBwOZtbP+70fMOWm2wbcPm7Ca4Nu79N95KVKDssuM19WMjOzDIeDmZllOBzMzCzD4WBmZhkOBzMzy6iZcJDUJOmwpHZJK6o9HjOzK1lNPMoqaQzwv4G/BDqAX0vaFhEHqzsyMxuuUt+XgNLfmfB3JaqnJsIBmAu0R8RrAJI2AosAh4PZKFXq+xJQ+jsT/q5E9Sgiqj0GJN0JNEXEven9V4D/HBH/ULBfC9CS3s4G9l/WgdauG4DT1R5EjfBncZE/i4v8WVz0qYj4eKmdauXMQUVqmdSKiLXAWgBJbRHReKkHNhr4s7jIn8VF/iwu8mdxkaS2cvarlRvSHcD0vPcNwMkqjcXM7IpXK+Hwa2CWpJmSxgHNwLYqj8nM7IpVE5eVIuKCpH8A/g0YA3wvIg6UaLb20o9s1PBncZE/i4v8WVzkz+Kisj6LmrghbWZmtaVWLiuZmVkNcTiYmVnGqAwHT7WRI+l7krolXfHf95A0XdIvJB2SdEDS8mqPqVokXS1pt6RX0mfxjWqPqZokjZH0sqSfVXss1STpd5L2SdpbzuOso+6eQ5pq4wh5U20AX7oSp9qQ9BfA28CGiJhd7fFUk6RpwLSIeEnSx4E9wOIr9L8LARMi4m1JHwV+BSyPiH+v8tCqQtIDQCMwMSK+UO3xVIuk3wGNEVHWlwFH45nDH6baiIj3gL6pNq44EfFL4PVqj6MWRERnRLyU1s8Bh4D66o6qOiLn7fT2o+k1uv4KrBBJDcDfAt+t9lhGm9EYDvXAibz3HVyh/xOw4iTNAD4DtFZ5KFWTLqXsBbqB7RFxpX4W3wa+DnxQ5XHUggB+LmlPmopoUKMxHMqaasOuTJI+BvwYuD8izlZ7PNUSEb0RcSu52QbmSrriLjtK+gLQHRF7qj2WGjE/Im4D/hpYli5LD2g0hoOn2rCi0vX1HwPfj4ifVHs8tSAi3gReAJqqO5KqmA98MV1r3wh8TtK/VHdI1RMRJ9OyG/gpuUv0AxqN4eCpNiwj3YRdBxyKiG9VezzVJKlO0qS0Ph74PPBqVQdVBRGxMiIaImIGuf9P7IyIL1d5WFUhaUJ6UANJE4C/osSs1qMuHCLiAtA31cYhYHMZU218KEn6IbAL+JSkDklLqz2mKpoPfIXcX4d70+tvqj2oKpkG/ELSb8j9MbU9Iq7oxziNqcCvJL0C7Ab+T0Q8P1iDUfcoq5mZXXqj7szBzMwuPYeDmZllOBzMzCzD4WBmZhkOBzOzGlDpiTQl9eY9uTfkx/39tJKZWQ2o9ESakt6OiI8Nt73PHMzMakCxiTQl/bGk59N8SP9X0p9crvE4HMzMatda4GsRMQf4H8CTQ2h7taQ2Sf8uafFQ/+GxQ21gZmaXXppE8s+BH+VmhwHgqrTt74CHizT7j4hYmNb/U0SclPRJYKekfRHx23L/fYeDmVlt+gjwZppdt580seSgk0vmTbT3mqQXyE1jX3Y4+LKSmVkNSlPOH5N0F+Qml5T06XLaSposqe8s4wZyc48N6VcRHQ5mZjVggIk0/yuwNE2Yd4Dyf/XyT4G21O4XwKND/clcP8pqZmYZPnMwM7MMh4OZmWU4HMzMLMPhYGZmGQ4HMzPLcDiYmVmGw8HMzDL+P7FMUxKhTSQPAAAAAElFTkSuQmCC",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "tsd = spst.norm.ppf(loc=25, scale=6, q=pn['throat.seed'])\n",
    "pn['throat.diameter'] = tsd*1e-6\n",
    "plt.hist(pn['throat.diameter'], edgecolor='k', density=True, alpha=0.5)\n",
    "plt.hist(pn['pore.diameter'], edgecolor='k', density=True, alpha=0.5)\n",
    "plt.xlim([0, 50e-6]);"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7c3c2104",
   "metadata": {},
   "source": [
    "Once the pore and throat diameters are specified, the next step is to define any dependent properties of interest, such as pore volume or throat length. These additional calculations tend to require that we assume a shape for the pores and throats.  It is not mandatory to use spheres and cylinders, though this is a common choice.  We could also work with cubic pores and cuboid throats, which occupy a large volume fraction for instance.  The choice of cubic shapes also happens to make the calculations much easier, for reasons explored below, so in this tutorial we'll assume cubic shapes.  Let's calculate the throat length, and pore surface area, since each of these illustrate very important concepts regarding the use of vectorized calculations."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "15cdc018",
   "metadata": {},
   "source": [
    "### Computing throat length\n",
    "\n",
    "Throat length is the pore-to-pore spacing, less the radius of each pore.  This can be found without the need for a for-loop using the following vectorization trick:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "9c8bc582",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[5.e-05 5.e-05 5.e-05 ... 5.e-05 5.e-05 5.e-05]\n"
     ]
    }
   ],
   "source": [
    "R1, R2 = (pn['pore.diameter'][pn.conns]/2).T\n",
    "L_total = np.sqrt(np.sum(np.diff(pn.coords[pn.conns], axis=1).squeeze()**2, axis=1))\n",
    "Lt = L_total - R1 - R2\n",
    "print(L_total)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f68b01d8",
   "metadata": {},
   "source": [
    "The above cell contains 3 complicated but powerful steps:\n",
    "1. The radii of the pores on each end of each throat are retrieved. `R1` and `R2` contain duplicates since each pore has numerous throats, so they appear once for each throat. This fact is used in step 3.\n",
    "2. The pore-to-pore distance is found by retrieving the coordinates of each pore, in the same was as was done for the radii. The Euclidean distance between each pair of pores is then computed by finding their difference (`np.diff`), squaring it, summing it (`np.sum`), then taking the square root (`np.sqrt`) of each. The `axis` argument is used throughout to tell numpy which way to apply the operation. This line is an example of how you must learn a *mini-language* to use numpy effectively. \n",
    "3. The length of each throat is found as the spacing between pores, less the radii of the pore on each end. This is where the duplicate values in `R1` and `R2` are necessary, since the radii of pore *i* must be subtracted from length of each of its neighboring throats.\n",
    "\n",
    "The main take-home message here is that throat properties can be computed in a vectorized way, even if some pore-properties are required. This avoids the use of a for-loop to scan through a list of throats followed by a nested for-loop to scan through each neighboring pore."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d57f31e0",
   "metadata": {},
   "source": [
    "### Computing pore surface areas\n",
    "The pore surface area is the total area of the cubic pore body, less the cross-sectional area of each neighboring throat. This can also be found without a for-loop, but requires knowing some deeper `numpy` functionality, known as [unbuffered in-place operations](https://numpy.org/doc/stable/reference/generated/numpy.ufunc.at.html):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "9850978b",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[9.08485305e-10 5.68134509e-09 2.33947201e-09 ... 6.57211706e-10\n",
      " 1.92152447e-09 1.72429278e-09]\n"
     ]
    }
   ],
   "source": [
    "At = pn['throat.diameter']**2\n",
    "SAp = (pn['pore.diameter']**2)*6\n",
    "np.subtract.at(SAp, pn.conns[:, 0], At)\n",
    "np.subtract.at(SAp, pn.conns[:, 1], At)\n",
    "print(SAp)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6a1f2c36",
   "metadata": {},
   "source": [
    "The above cell contains 2 lines of importance, which each do almost the same thing:\n",
    "1. The first line subtracts the throat cross-sectional area from each pore listed in the first column of the `pn.conns` array. Since a given pore is connected to potentially many throats, the subtraction must be done using `np.substract.at` which is a special version of the subtract function that subtracts every value in `At` from the locations in `SAp` indicated by `pn.conn[:, 0]`, and it does so in a cumulative fashion. Thus if pore *i* appears in `pn.conns[:, 0]` more than once, then more than one value of `At` is removed. The operation is performed *in-place* so that no array is returned.\n",
    "2. Recall that `pn.conns` contains only the upper-triangular entries of the adjacency matrix, so this process only gets half of the connections. This means that the pore connections found in `pn.conns[:, 1]` must also be analyzed."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4ef26402",
   "metadata": {},
   "source": [
    "## Using Pore-scale Models from the Library\n",
    "\n",
    "The above section is quite lengthy, but lays bare the process of computing geometric properties of a network for illustration purposes.  In this section we'll utilize OpenPNM's library of 'pore-scale' models to get the same job done much more easily. Start by generating a fresh network:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "4c7e5341",
   "metadata": {},
   "outputs": [],
   "source": [
    "np.random.seed(0)\n",
    "pn = op.network.Cubic([20, 20, 20], spacing=5e-5)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "460a0434",
   "metadata": {},
   "source": [
    "First let's assign a random number to each pore, but instead of using `np.random.rand` directly, we'll use a pore-scale model:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "ba5de6a1",
   "metadata": {},
   "outputs": [],
   "source": [
    "f = op.models.geometry.pore_seed.random\n",
    "pn.add_model(propname='pore.seed', \n",
    "             model=f,\n",
    "             seed=None,  # Seed value provided to numpy's random number generator.\n",
    "             num_range=[0.01, 0.99],)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9421fc7f",
   "metadata": {},
   "source": [
    "```{note} **Where do models go?**  \n",
    "\n",
    "  We'll look more closely at models later in this tutorial, but it's worth pointing out that the `add_model` method collects all the arguments provided and stores them in the `models` attribute of the object. Later, when `regenerate_models` is called, it looks into the `models` attribute and fetches the model (`f`) and the given arguments, calls the function, collects the returned result, and stores them in `pn[propname]`. You can see a list of models applied to the object with `print(pn.models)`. \n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cb01c08b",
   "metadata": {},
   "source": [
    "Let's have each throat inherit the minimum seed value found in each of its neighboring pores, for which OpenPNM provides a model:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "5529e24c",
   "metadata": {},
   "outputs": [],
   "source": [
    "f = op.models.geometry.throat_seed.from_neighbor_pores\n",
    "pn.add_model(propname='throat.seed', \n",
    "             model=f,\n",
    "             prop='pore.seed',\n",
    "             mode='min')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "72d55b9b",
   "metadata": {},
   "source": [
    "```{tip} **Using shift-tab to see the docstring** \n",
    "\n",
    "  In the above two code blocks the models were assigned to `f` first, then `f` was passed to the `model` argument. This is helpful for two reasons.  (1) It helps keep the line length below Python's preferred limit of 78 characters, and (2) it makes it possible to see the docstring of the model by putting the cursor at the end of the first line and hitting `shift-tab`. Seeing the docstring really helps to understand what a model does and what arguments are required.\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2b9bec66",
   "metadata": {},
   "source": [
    "Now we can compute pore and throat sizes from distributions, which are also provided as OpenPNM models:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "3ddc9a3d",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "f = op.models.geometry.pore_size.normal\n",
    "pn.add_model(propname='pore.diameter',\n",
    "             model=f,\n",
    "             scale=1e-5, \n",
    "             loc=2.5e-5,\n",
    "             seeds='pore.seed')\n",
    "plt.hist(pn['pore.diameter'], edgecolor='k');"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a7232364",
   "metadata": {},
   "source": [
    "And similarly we fetch a model for the throat sizes as well:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "id": "0a2adc8e",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "f = op.models.geometry.throat_size.normal\n",
    "pn.add_model(propname='throat.diameter',\n",
    "             model=f,\n",
    "             scale=1e-5, \n",
    "             loc=2.5e-5)\n",
    "plt.hist(pn['pore.diameter'], edgecolor='k', density=True, alpha=0.5)\n",
    "plt.hist(pn['throat.diameter'], edgecolor='k', density=True, alpha=0.5);"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "27579da1",
   "metadata": {},
   "source": [
    "Now that we have pore and throat sizes, we can compute their volumes (and other properties). The volume will depend on the shape of the pores and throats.  In OpenPNM we do not explicitly track such *shapes*.  Instead we offer several models that calculate the property of interest for a given shape. This is illustrated below:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "id": "01d0e7e7",
   "metadata": {},
   "outputs": [],
   "source": [
    "f = op.models.geometry.throat_length.spheres_and_cylinders\n",
    "pn.add_model(propname='throat.length',\n",
    "             model=f)\n",
    "f1 = op.models.geometry.pore_volume.sphere \n",
    "pn.add_model(propname='pore.volume',\n",
    "             model=f1)\n",
    "f2 = op.models.geometry.throat_volume.cylinder\n",
    "pn.add_model(propname='throat.volume',\n",
    "             model=f2)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f9628d8c",
   "metadata": {},
   "source": [
    "```{warning} **Spherical pores overlap with their throats**\n",
    "\n",
    "  A spherical pore will always have a region of overlap with its connected throats. The volume of this region will be double counted if an extra step is not taken. \n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "id": "94e06d54",
   "metadata": {},
   "outputs": [],
   "source": [
    "f = op.models.geometry.throat_length.spheres_and_cylinders\n",
    "pn.add_model(propname='throat.length',\n",
    "             model=f)\n",
    "f1 = op.models.geometry.pore_volume.sphere \n",
    "pn.add_model(propname='pore.volume',\n",
    "             model=f1)\n",
    "f2 = op.models.geometry.throat_volume.cylinder\n",
    "pn.add_model(propname='throat.total_volume',\n",
    "             model=f2)\n",
    "f3 = op.models.geometry.throat_volume.lens\n",
    "pn.add_model(propname='throat.lens_volume',\n",
    "             model=f3)\n",
    "f4 = op.models.misc.difference\n",
    "pn.add_model(propname='throat.volume',\n",
    "             model=f4,\n",
    "             props=['throat.total_volume', 'throat.lens_volume'])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "36d6d236",
   "metadata": {},
   "source": [
    "We can inspect some of these values to make sure they are making sense:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "id": "682f95fd",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Volumes of full throats: [4.06671058e-12 4.49724923e-12 4.03844746e-12]\n",
      "Volumes of lenses: [6.92245838e-15 8.40091924e-15 7.59556144e-15]\n",
      "Actual throat volumes: [4.05978813e-12 4.48884831e-12 4.03085190e-12]\n"
     ]
    }
   ],
   "source": [
    "print(\"Volumes of full throats:\", pn['throat.total_volume'][:3])\n",
    "print(\"Volumes of lenses:\", pn['throat.lens_volume'][:3])\n",
    "print(\"Actual throat volumes:\", pn['throat.volume'][:3])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "21dda2c5",
   "metadata": {},
   "source": [
    "## Using Predefined Collections of Models\n",
    "\n",
    "The process of selecting all the correct models from the `models` library can be tedious and error prone. In OpenPNM V3 we have introduced the concept of model *collections*, which are predefined dictionaries of models that form a complete and correct geometry. For instance, there is a collection called `spheres_and_cylinders`, which contains all the needed models to describe this geometry.  \n",
    "\n",
    "These collections are found under `openpnm.models.collections`, and their use is outlined below:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "id": "8ff9e8b6",
   "metadata": {},
   "outputs": [],
   "source": [
    "pn = op.network.Cubic(shape=[20, 20, 20], spacing=5e-5)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bdb85f3e",
   "metadata": {},
   "source": [
    "The models *collection* is fetched as follows:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "id": "0260c363",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'pore.diameter': {'model': <function product at 0x0000026C1FECB790>,\n",
      "                   'props': ['pore.max_size', 'pore.seed']},\n",
      " 'pore.max_size': {'iters': 10,\n",
      "                   'model': <function largest_sphere at 0x0000026C20E30790>},\n",
      " 'pore.seed': {'element': 'pore',\n",
      "               'model': <function random at 0x0000026C1FEC2E50>,\n",
      "               'num_range': [0.2, 0.7],\n",
      "               'seed': None},\n",
      " 'pore.volume': {'model': <function sphere at 0x0000026C20E30E50>,\n",
      "                 'pore_diameter': 'pore.diameter'},\n",
      " 'throat.cross_sectional_area': {'model': <function cylinder at 0x0000026C20E3C430>,\n",
      "                                 'throat_diameter': 'throat.diameter'},\n",
      " 'throat.diameter': {'factor': 0.5,\n",
      "                     'model': <function scaled at 0x0000026C1FECB820>,\n",
      "                     'prop': 'throat.max_size'},\n",
      " 'throat.diffusive_size_factors': {'model': <function spheres_and_cylinders at 0x0000026C20E9AD30>,\n",
      "                                   'pore_diameter': 'pore.diameter',\n",
      "                                   'throat_diameter': 'throat.diameter'},\n",
      " 'throat.hydraulic_size_factors': {'model': <function spheres_and_cylinders at 0x0000026C20E8F820>,\n",
      "                                   'pore_diameter': 'pore.diameter',\n",
      "                                   'throat_diameter': 'throat.diameter'},\n",
      " 'throat.length': {'model': <function spheres_and_cylinders at 0x0000026C20E56160>,\n",
      "                   'pore_diameter': 'pore.diameter',\n",
      "                   'throat_diameter': 'throat.diameter'},\n",
      " 'throat.lens_volume': {'model': <function lens at 0x0000026C20E620D0>,\n",
      "                        'pore_diameter': 'pore.diameter',\n",
      "                        'throat_diameter': 'throat.diameter'},\n",
      " 'throat.max_size': {'mode': 'min',\n",
      "                     'model': <function from_neighbor_pores at 0x0000026C1FECBA60>,\n",
      "                     'prop': 'pore.diameter'},\n",
      " 'throat.total_volume': {'model': <function cylinder at 0x0000026C20E56EE0>,\n",
      "                         'throat_diameter': 'throat.diameter',\n",
      "                         'throat_length': 'throat.length'},\n",
      " 'throat.volume': {'model': <function difference at 0x0000026C1FECB430>,\n",
      "                   'props': ['throat.total_volume', 'throat.lens_volume']}}\n"
     ]
    }
   ],
   "source": [
    "from pprint import pprint\n",
    "mods = op.models.collections.geometry.spheres_and_cylinders\n",
    "pprint(mods)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "505c0189",
   "metadata": {},
   "source": [
    "The print-out of the dictionary is not very nice, but it can be seen that the keys are the model names, and the values are the model itself and the various arguments for the model.  This dictionary can be added to the network using the `add_models_collection` method as follows:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "id": "3756bc09",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "══════════════════════════════════════════════════════════════════════════════\n",
      "net : <openpnm.network.Cubic at 0x26c22f00900>\n",
      "――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――\n",
      "  #  Properties                                                   Valid Values\n",
      "――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――\n",
      "  2  pore.coords                                                   8000 / 8000\n",
      "  3  throat.conns                                                22800 / 22800\n",
      "  4  pore.coordination_number                                      8000 / 8000\n",
      "  5  pore.max_size                                                 8000 / 8000\n",
      "  6  throat.spacing                                              22800 / 22800\n",
      "  7  pore.seed                                                     8000 / 8000\n",
      "  8  pore.diameter                                                 8000 / 8000\n",
      "  9  throat.max_size                                             22800 / 22800\n",
      " 10  throat.diameter                                             22800 / 22800\n",
      " 11  throat.cross_sectional_area                                 22800 / 22800\n",
      " 12  throat.hydraulic_size_factors                               22800 / 22800\n",
      " 13  throat.diffusive_size_factors                               22800 / 22800\n",
      " 14  throat.lens_volume                                          22800 / 22800\n",
      " 15  throat.length                                               22800 / 22800\n",
      " 16  throat.total_volume                                         22800 / 22800\n",
      " 17  throat.volume                                               22800 / 22800\n",
      " 18  pore.volume                                                   8000 / 8000\n",
      "――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――\n",
      "  #  Labels                                                 Assigned Locations\n",
      "――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――\n",
      "  2  pore.surface                                                         2168\n",
      "  3  throat.surface                                                       4332\n",
      "  4  pore.left                                                             400\n",
      "  5  pore.right                                                            400\n",
      "  6  pore.front                                                            400\n",
      "  7  pore.back                                                             400\n",
      "  8  pore.bottom                                                           400\n",
      "  9  pore.top                                                              400\n",
      "――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――\n"
     ]
    }
   ],
   "source": [
    "pn.add_model_collection(mods)\n",
    "pn.regenerate_models()\n",
    "print(pn)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6814eb17",
   "metadata": {},
   "source": [
    "## Customizing Models by Overwriting Them or Their Arguments\n",
    "\n",
    "The pre-written models and collections included with OpenPNM are helpful, but you'll almost always want to adjust some of the models to suit a specific application. This can be done by either altering the arguments of existing models, or by overwriting them all together. \n",
    "\n",
    "Let's first look at replacing a model with one of our choice.  The `spheres_and_cylinders` collection uses a random distribution of pore sizes, bounded between 0 and the distance to the nearest neighbor. This can be inspected by printing the specific model as follows:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "id": "24933005",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――\n",
      "Property Name             Parameter                 Value\n",
      "――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――\n",
      "pore.diameter             model:                    product\n",
      "                          props:                    ['pore.max_size', 'pore.seed']\n",
      "                          regeneration mode:        deferred\n",
      "――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――\n"
     ]
    }
   ],
   "source": [
    "print(pn.models['pore.diameter@all'])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "99103ed9",
   "metadata": {},
   "source": [
    "```{note} **The @ Notation**\n",
    "\n",
    "  The `'@all'` that has been added to the model name is new in Version 3 and means that this model should be applied to pore that have the label `'pore.dall'`. This will be explained in detail in the next tutorial. \n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "29bf7355",
   "metadata": {},
   "source": [
    "Let's replace this with a normal distribution. This can be done with the `add_model` method as before. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "id": "e68addce",
   "metadata": {},
   "outputs": [],
   "source": [
    "f = op.models.geometry.pore_size.normal\n",
    "pn.add_model(propname='pore.diameter',\n",
    "             model=f,\n",
    "             scale=1e-5, \n",
    "             loc=2.5e-5,\n",
    "             seeds='pore.seed')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "327e87a3",
   "metadata": {},
   "source": [
    "Now print the model again to ensure it was updated:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "id": "e687fdd7",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――\n",
      "Property Name             Parameter                 Value\n",
      "――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――\n",
      "pore.diameter             model:                    normal\n",
      "                          scale:                    1e-05\n",
      "                          loc:                      2.5e-05\n",
      "                          seeds:                    pore.seed\n",
      "                          regeneration mode:        normal\n",
      "――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――\n"
     ]
    }
   ],
   "source": [
    "print(pn.models['pore.diameter@all'])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "03b97a60",
   "metadata": {},
   "source": [
    "And let's inspect the values:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "id": "abf73f2b",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.hist(pn['pore.diameter'], edgecolor='k');"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4635252e",
   "metadata": {},
   "source": [
    "This distribution is quite truncated, due to the `'pore.seed'` values that were used.  Let's reach into that model and change this.  First print the model:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "id": "d5e4fac7",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――\n",
      "Property Name             Parameter                 Value\n",
      "――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――\n",
      "pore.seed                 model:                    random\n",
      "                          element:                  pore\n",
      "                          num_range:                [0.2, 0.7]\n",
      "                          seed:                     None\n",
      "                          regeneration mode:        deferred\n",
      "――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――\n"
     ]
    }
   ],
   "source": [
    "print(pn.models['pore.seed@all'])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9d70dd11",
   "metadata": {},
   "source": [
    "We can see that the `num_range` argument is quite constrained, so let's change it. Each model is itself a dictionary, so we can overwrite as follows:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "id": "e316f20c",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "pn.models['pore.seed@all']['num_range'] = [0.01, 0.99]\n",
    "pn.regenerate_models()\n",
    "plt.hist(pn['pore.diameter'], edgecolor='k');"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e880f2ee",
   "metadata": {},
   "source": [
    "## Introduction to the Dependency Handler\n",
    "\n",
    "Pore-scale models clearly make life easier since you don't have to produce the complex numpy functions by hand each time, but this is not even their best feature! The main benefit of pore-scale models is that they can be *recomputed* automatically. For instance, if we re-run the `'pore.seed'` model, then all the other models that depend on `'pore.seed'` will automatically be recomputed as well. This all occurs when we call `regenerate_models`, as demonstrated below:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "id": "07e6f7fe",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[0.15319619 0.0328116  0.2287953  ... 0.23887453 0.8411705  0.10988224]\n",
      "[6.59011212e-06 6.59011212e-06 1.75717988e-05 ... 1.13561876e-05\n",
      " 2.66940036e-05 1.27284536e-05]\n"
     ]
    }
   ],
   "source": [
    "pn = op.network.Cubic(shape=[20, 20, 20], spacing=5e-5)\n",
    "pn.add_model(propname='pore.seed',\n",
    "             model=op.models.geometry.pore_seed.random)\n",
    "pn.add_model(propname='pore.diameter',\n",
    "             model=f,\n",
    "             scale=1e-5, \n",
    "             loc=2.5e-5,\n",
    "             seeds='pore.seed')\n",
    "pn.add_model(propname='throat.seed',\n",
    "             model=op.models.geometry.throat_seed.from_neighbor_pores,\n",
    "             prop='pore.seed')\n",
    "pn.add_model(propname='throat.diameter',\n",
    "             model=f,\n",
    "             scale=1e-5, \n",
    "             loc=2.5e-5,\n",
    "             seeds='throat.seed')\n",
    "print(pn['pore.seed'])\n",
    "print(pn['throat.diameter'])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "id": "95915c96",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[0.36618201 0.35063831 0.40236746 ... 0.58822388 0.42461491 0.9016327 ]\n",
      "[2.11640227e-05 2.11640227e-05 2.20171387e-05 ... 2.57748463e-05\n",
      " 2.30989878e-05 3.79091080e-05]\n"
     ]
    }
   ],
   "source": [
    "pn.regenerate_models()\n",
    "print(pn['pore.seed'])\n",
    "print(pn['throat.diameter'])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8ed8615a",
   "metadata": {},
   "source": [
    "As we can see above the initial values of `'pore.seed'` and `'throat.diameter'` are both changed after calling `regenerate_models()`. OpenPNM does this automatically by inspecting the arguments to each function. \n",
    "\n",
    "Inspecting the `add_model` calls above we can see:\n",
    "\n",
    "1. The `'throat.seed'` model takes `'pore.seed'` as an argument\n",
    "2. The `'throat.diameter'` model takes `'throat.seed'` as an argument\n",
    "3. The `'pore.diameter'` models takes `'pore.seed'` as an argument\n",
    "\n",
    "So when `regenerate_models` is called it first re-runs the `'pore.seed'` model, which has no dependencies, then it re-runs the `'throat.seed'` model, then `'throat.diameter'`, in that order based on their dependencies. It also calls `'pore.diameter'`, but no other models depend on this. The dependency handling is done by creating a graph or network using `networkx` then do a special sort to find the top of the tree and all the downstream dependencies.  This can be roughly visualized using:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "id": "4080b43e",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "pn.models.dependency_map(style='planar');"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c641bb09",
   "metadata": {},
   "source": [
    "The green circles are pore properties and the orange squares are throat properties. We can also see that there are two models which are not dependent on anything else: `'throat.spacing'` and `'pore.coordination_number'`.  These are added to all networks during generation but not run, hence their values do no show up when doing `print(pn)`."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bcc3cfce",
   "metadata": {},
   "source": [
    "It is also possible to make your own plot if you wish, by retrieving the dependency graph then calling the `networkx` plotting function of your choice:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "id": "fde9676e",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 360x360 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import networkx as nx\n",
    "g = pn.models.dependency_graph()\n",
    "fig, ax = plt.subplots(figsize=[5, 5])\n",
    "nx.draw_networkx\n",
    "nx.draw_planar(g, labels={k: k for k, v in g.nodes.items()}, ax=ax)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.13"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
